import 'pinia'
import { ComponentInternalInstance, ComponentPublicInstance } from 'vue'
interface Data {
  [key: string]: any
}

/**渐变方向 left:右->左，right:左->右。top:下->上，bottom:上->下。 */
export type linearType = 'left' | 'right' | 'bottom' | 'top' | ''
/**渐变色调，light,dark,accent亮系渐变和深色渐变。 */
export type linearDeepType = 'accent' | 'dark' | 'light'

/**边线的访问 */
export type borderDirectionType =
  | 'all'
  | 'bottom'
  | 'bottomleft'
  | 'bottomright'
  | 'left'
  | 'leftright'
  | 'right'
  | 'right'
  | 'top'
  | 'topbottom'
  | 'topleft'
  | 'topright'
  | 'x'
  | 'y'
/**边线的样式 */
export type borderStyleType = 'solid' | 'dashed' | 'dotted'

type componentKey = 'app' | 'button' | 'card' | 'tag' | 'sheet'
/**定义对象字段的键值只能是规定的组件名称。 */
type componentKeys = Partial<Record<componentKey, Tmui.components.all>>

declare global {
  interface Uni {
    /**
     * tmui3.0 函数库
     * https://tmui.design
     */
    $tm: tmUtil
  }
  namespace UniNamespace {
    interface CanvasToTempFilePathOptions {
      // @ts-ignore
      canvas?: CanvasContext
    }
    interface CanvasContext {
      width: number
      height: number
      /**dpr,屏幕的倍率 */
      dpr: number
      /**nvue的gcanvas函数 */
      toTempFilePath(
        any0: any,
        any1: any,
        any2: any,
        any3: any,
        any4: any,
        any5: any,
        any6: any,
        any7: any,
        any8: any
      ): void
    }
    interface NodesRef {
      /**节点，微信小程序上 */
      node(callback?: (result: any) => void): SelectorQuery
      /**需要读取的字段属性 */
      fields(fields: NodeField, callback?: (result: NodeInfo) => void): SelectorQuery
    }
    interface NodeField {
      /**包含的节点，部分小程序上会返回。 */
      node?: boolean
    }
  }

  namespace Tmui {
    interface fetchNetConfigType {
      /**
       * 请求的数据，query,或者body，都可传递对象。自动转换数据格式。
       */
      data?: any
      /**
       * 头部数据。
       */
      header?: any
      /**
       * 请求方式
       */
      method?: fetchConfigMethod
      /**
       * 定义成功的服务器返回的状态码成功的标志
       */
      statusCode?: number
      /**
       * 从返回的结果读取的数据字段，默认全部返回，
       * 如果指定了就会读取指定字段
       * 比如你的结果返回{code,data,msg},如果你指定：['data'],结果集中只返回data数据
       * 如果是['data',code],结果集中只返回{data,code}
       */
      pick?: string[]
      /**
       * 是否监视参数的变化，如果参数发生了变化将会重新发起请求
       */
      watchRefresh?: boolean
      /**
       * 如果不配置或者配置,默认为all
       */
      toast?: 'fail' | 'success' | 'all'
      /**
       * 是否显示操作后的提示,默认为true
       */
      showToast?: boolean
      /**
       * 读取提示信息的字段，如果读取不到会显示自动的文字。默认为msg
       */
      toastKey?: string
      /**
       * 是否显示加载框,默认为true。
       */
      showLoading?: boolean
    }

    /**tmui配置表 */
    interface tmuiConfig {
      /** 自动跟随系统暗黑 */
      autoDark?: boolean
      /** 开启全局分离功能，默认关闭 */
      shareDisable?: boolean
      /**主题列表 */
      theme?: {}
      /**细化全局的主题配置表 */
      themeConfig?: {
        /**暗黑模式下的一些统一配置 */
        dark?: {
          /**一般的卡片项目暗黑背景 */
          cardColor?: string
          /**输入框，表单等暗黑背景 */
          inputColor?: string
          /**禁用输入框，表单等暗黑背景 */
          disableColor?: string
          /**暗黑下的页面背景 */
          bodyColor?: string
          /**文本禁用色. */
          textDisableColor?: string
        }
        /**
         * app整体字体大小的调整比例，
         * 只对使用tm-text组件以及自身组件的字号才会有效果
         *
         * */
        globalFontSizeRatio?: number
        /** 是否关闭弹层背景的模糊 */
        overflowBlur?: false
        /**
         * 针对不同的主题配置详细的配色方案。
         * 注意这里影响的时主题计算功能的配置
         */
        theme?: {
          /**（如果该组件默认有值就会使用下列属性，如果组件默认为0不会使用。） */
          [key: string]: {
            /**待考虑编辑2023-2-18 00:23:35 */
          }
        }
        /**各个组件的统一配置 */
        component?: componentKeys
      }
      /**router路由拦截代替外置文件 */
      router?: {
        /**页面访问前执行 */
        useTmRouterBefore(arg: beforeRouterOpts): void
        /**页面访问后执行 */
        useTmRouterAfter(arg: beforeRouterOpts): void
      }
      /**用户自定义全局数据 */
      custom?: {
        [key: string]: any
      }
    }
    interface beforeRouterOpts {
      path: string | null //当前页面路径，不含前缀 /
      opts?: any //页面参数
      openType?: string //当前页面打开的类型
      context: ComponentPublicInstance | null
    }
    /**actionMenu组件项目类型 */
    interface tmActionMenu {
      text?: string
      disabled?: boolean
      /** 各家小程序的openType。 */
      openType?: string
      [key: string]: any
    }
    interface tmAlert {
      icon?: string
      title?: string
      content?: string
    }
    interface tabs {
      key?: string | number
      title?: string
      icon?: string
      dot?: boolean
      count?: string | number
      dotColor?: string
      [key: string]: any
    }
    interface skuItem {
      title: string
      id: string | number
      num: number
      children: skuItem[]
    }
    interface sku {
      data: skuItem[]
      product: {
        id: string
        title: string
        num: number
        max_buy: number
        /** 原价 */
        price: number
        /** 优惠价 */
        salePrice: 54
        tip: string
        img: string
      }[]
    }

    interface tmFormSubmitResult {
      data: { [key: string]: any }
      isPass: boolean
      result: {
        message: string //校验后的提示文本
        validator: boolean //是否校验通过
      }[]
    }
    interface tmFormRules {
      validator?: Function | boolean //检验函数。可以是Promise异步回调。
      required?: boolean //是否必填。
      message?: string //检验不合格时的文本
      type?: string //校验类型.
      [key: string]: any
    }
    /**组件的配置 */
    namespace components {
      type all = button & sheet
      interface button {
        round?: number
        shadow?: number
        color?: string
      }
      interface sheet {}
    }
  }
}
declare module 'pinia' {
  export interface PiniaCustomProperties {
    tmuiConfig: Tmui.tmuiConfig
  }
  export interface PiniaCustomStateProperties {
    tmuiConfig: Tmui.tmuiConfig
  }
}

export type pagesCustomType = 'default' | 'custom'
export interface pagesType {
  //页面地址
  path: string
  //导航栏模式
  custom: pagesCustomType
  navigationBarBackgroundColor: string
  navigationBarTextStyle: string
  subPackages?: Array<any>
}
export interface tabBarItemType {
  pagePath: string
  iconPath: string
  selectedIconPath: string
  text: string
}
export interface tabBarType {
  color: string
  selectedColor: string
  borderStyle: string
  backgroundColor: string
  list?: Array<tabBarItemType>
}
export interface beforeRouterOpts {
  path: string | null //当前页面路径，不含前缀 /
  opts?: any //页面参数
  openType?: string //当前页面打开的类型
  context: ComponentPublicInstance | null
}
type fetchConfigResponseType = 'arraybuffer' | 'text'
type fetchConfigDataType = 'json' | 'text'
type fetchConfigMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'CONNECT' | 'HEAD' | 'OPTIONS' | 'TRACE'

interface fetchConfigSuccessType {
  data: object | string | ArrayBuffer
  statusCode: number
  header: object
  cookies: Array<string>
}
interface fetchConfig {
  url?: string
  data?: object | string | ArrayBuffer
  header?: object
  method?: fetchConfigMethod
  timeout?: number
  dataType?: fetchConfigDataType
  responseType?: fetchConfigResponseType
  sslVerify?: boolean
  withCredentials?: boolean
  firstIpv4?: boolean
  success?: Function
  fail?: Function
  complete?: Function
}
type openUrlType = 'navigate' | 'redirect' | 'reLaunch' | 'switchTab' | 'navigateBack'
declare interface Touch {
  readonly clientX: number
  readonly clientY: number
  readonly force: number
  readonly identifier: number
  readonly pageX: number
  readonly pageY: number
  readonly radiusX: number
  readonly radiusY: number
  readonly rotationAngle: number
  readonly screenX: number
  readonly screenY: number
  readonly target: EventTarget
  readonly x: number
  readonly y: number
}

declare interface TouchEvent {
  readonly changedTouches: TouchList
}

type tmUtil = {
  //pagejson下的pages配置。
  pages: Array<{ path: string; custom: 'custom' | 'default' }>
  //pagejson下的配置。
  tabBar: tabBarType
  globalNavStyle: 'custom' | 'default'
  /**
   * 判断是否是颜色值
   * @param color 颜色值
   */
  isColor(color: string): boolean
  /**
   * 国际化
   * @param key 关键字
   * @return 语言值
   */
  language(key: string): string
  fetch: {
    /**
     * GET请求
     * @param url 请求地址
     * @param data 请求的数据
     * @param opts 请求的配置
     * @help https://tmui.design/doc/JSTool/fetch.html
     */
    get(
      url: string,
      data?: object,
      opts?: fetchConfig
    ): Promise<UniApp.GeneralCallbackResult | UniApp.RequestSuccessCallbackResult>
    /**
     * POST请求
     * @param url 请求地址
     * @param data 请求的数据
     * @param opts 请求的配置
     * @help https://tmui.design/doc/JSTool/fetch.html
     */
    post(
      url: string,
      data?: object,
      opts?: fetchConfig
    ): Promise<UniApp.GeneralCallbackResult | UniApp.RequestSuccessCallbackResult>
    /**
     * 自定义请求
     * @param cog 请求的配置
     * @param beforeFun 请求前执行的函数
     * @param afterFun 请求后执行的函数
     * @param complete 请求完成的函数
     * @help https://tmui.design/doc/JSTool/fetch.html
     */
    request(
      cog: fetchConfig,
      beforeFun?: Function,
      afterFun?: Function,
      complete?: Function
    ): Promise<UniApp.GeneralCallbackResult | UniApp.RequestSuccessCallbackResult>
  }
  /**
   * tmui3.0函数工具
   */
  u: {
    /**
     * 检测是否是数字
     * @param arg 待检测的字符
     * @param defaultNum 0,如果不符合值时设置默认值
     * @returns number类型数值
     */
    isNumber(arg: string | number | undefined | null, defaultNum: number): number

    /**
     * 检测是否是字符串
     * @param arg 待检测的字符
     * @param defaultNum 默认"",如果不符合值是设置默认值
     * @returns 字符串
     */
    isString(arg: string | number | undefined | null, defaultStr: string): string

    /**
     * 把一个数字进行分页返回数字数组
     * @param total 总数
     * @param pageSize 分页大小
     * @returns 数字数组
     */
    paginate(total: number, pageSize: number): number[]

    /**
     * 取对象数据值（可深层次取值）
     * @example getValue(data,"a.b.c")
     * @param data 对象数据
     * @param keys 键值
     * @returns 返回值
     * @description 注意不会去改变原来的数据
     */
    getValue(data: Data, keys: string): any
    /**
     * 设置对象键值（可深层次设置值）
     * @example setValue(data,"a.b.c","haha")
     * @param data 对象数据
     * @param keys 键值
     * @returns 修改后的对象数据。
     * @description 改变原来的数据
     */
    setValue(data: Data, keys: string, value: any): void
    /**
     * 计算并返回一个对象中最大的层级数
     * @param data 待检测对象数据
     * @returns 最大层级数
     */
    getMaxDepth(data: Data): number

    /**
     * 预览图片。
     * @param {Object} url 必填 当前预览的图片链接。
     * @param {Object} list 可以是url数组，也可以是对象，数据比如：["http:url"] or [{url:"https:url",...}]
     * @param {Object} rangKey 如果list是对象数组，需要提供url字段。
     */
    preview(url: string, list?: Array<string>, rangKey?: string): void

    /**
     * 数据分组
     * @param {Array} oArr - 原数组列表
     * @param {Number} length - 单个数组长度
     * @return {Array}  arr - 分组后的新数组
     */
    splitData<T>(arr: Array<T>, size: number): Array<T[]>

    /**
     * 剩余时间格式化
     * @param {Number} t - 剩余多少秒
     * @return {Object}  format - 格式后的天时分秒对象
     */
    timeMuch(t: number): string
    /**
     * 获取时间距离当前时间
     * @param timestamp 当前时间
     * @return 返回比如：不久前，1年前这样的格式文本
     */
    getDateToNewData(timestamp?: number | string | Date): string
    /**
     * 打电话
     * @param {String<Number>} phoneNumber - 数字字符串
     * @return Promise<boolean>
     */
    callPhone(phoneNumber: string): Promise<boolean | any>
    /**
     * 调起客户端相机扫码。
     * @param {Boolean} onlyFromCamera true 是否只允许相机扫码识别
     * @param {Array<string>} scanType ['barCode', 'qrCode', 'datamatrix','datamatrix']
     * @returns Promise 成功返回相关数据结构
     */
    scanCode(onlyFromCamera: boolean, scanType: Array<any>): Promise<UniApp.ScanCodeSuccessRes | string>
    /**
     * 设置剪切板内容。
     * @param {String} data
     * @returns Promise true/false
     */
    setClipboardData(data: string): Promise<boolean | string>
    /**
     * 获取剪切板内容
     * @returns Promise 剪切板内容
     */
    getClipboardData(): Promise<string | boolean>
    /**
     * 设置cookie数据
     * @param {String} key 键值
     * @param {String} data 值
     * @returns Boolean
     */
    setCookie(key: string, data: any): boolean
    /**
     * 删除一个本地cookie
     * @param {String} key 键值
     * @returns Boolean
     */
    delCookie(key: string): boolean
    /**
     * 获取一个cookie数据
     * 如果存入的是对象，返回的也是对象。如果是string返回的也是字符串。
     * @param {String} key 键
     * @returns json/string
     */
    getCookie(key: string): Object | string
    /**
     * 向地址连接追加参数。
     * @param {string} uri 网址
     * @param {string} key 字段
     * @param {string} value 字段值
     * @returns 网址
     */
    httpUrlAddKey(uri: string, key: string, value: string): string
    /**
     * 取url参数
     * @param {string} uri 网址
     * @param {string} key 字段
     * @returns string|undefined
     */
    getQueryString(url: string, key: string): string
    /**
     * 唯一标识
     * @param rdix 1 随机因子
     * @param length  12 取的长度
     * @param isAddStr false 是否限制随机结果中的长度,不允许输出长度
     * @returns String
     */
    getUid(rdix?: number, length?: number, isAddStr?: boolean): number | string
    /**
     * 防抖
     * 防抖原理：在一定时间内，只有最后一次操作，再过wait毫秒后才执行函数
     * @param {Function} func 要执行的回调函数
     * @param {Number} wait 延迟的时间
     * @param {Boolean} immediate 是否要立即执行
     */
    debounce(func: Function, wait?: number, immediate?: boolean): void
    /**
     * 节流
     * 节流原理：在一定时间内，只能触发一次
     * @param {Function} func 要执行的回调函数
     * @param {Number} wait 延时的时间
     * @param {Boolean} immediate 是否立即执行
     * @return void
     */
    throttle(func: Function, wait?: number, immediate?: boolean, timer?: number, flags?: boolean): void
    /**
     * 深度克隆
     * @param {T} data 待大克隆复制的数据
     * @return {T} any
     */
    deepClone<T>(data: T): T
    /**
     * 等同：queryDom
     */
    quereyDom(t: ComponentInternalInstance, node: string): Promise<UniApp.NodeInfo | UniApp.NodeInfo[]>
    /**
     * 查询文档节点信息
     * @param t Vue上下文对象
     * @param node 提供带#的id比如：'#id',在nvue中应该是元素上写明ref='id'
     * @returns vue页面返回查询的节点信息，nvue返回weex的节点信息。
     */
    queryDom(t: ComponentInternalInstance, node: string): Promise<UniApp.NodeInfo | UniApp.NodeInfo[]>
    /**
     * 深度合并对象
     * @param FirstOBJ 需要合并的对象
     * @param SecondOBJ 被合并的对象
     * @returns 返回合并后的对象
     */
    deepObjectMerge(FirstOBJ: Record<string, any>, SecondOBJ: Record<string, any>): Record<string, any>
    /**
     * 是否是手机号码
     * @param phone 号码
     * @returns Boolean
     */
    isPhone(phone: string | number): boolean
    /**
     * 是否含有中文
     * @param s 字符串
     * @returns Boolean
     */
    isChina(s: string): boolean
    /**
     * 是否为空
     * @description 判断是否是null,对象是否为空，数组是否为空。是否为 undefaind，是否为 “”空字符串。
     * @param s 任意
     */
    isEmpty(s: any): boolean
    /**
     * 是否邮箱
     * @param s 字符串
     * @returns Boolean
     */
    isEmail(s: string): boolean
    /**
     * 是否身份证号
     * @param val 字符号或者数字
     * @returns Boolean
     * @author https://cloud.tencent.com/developer/article/1114323
     */
    isIdCard(val: string | number): boolean
    /**
     * 是否车牌
     * @description 蓝牌5位，绿牌6位。
     * @param s 字符串
     * @returns Boolean
     */
    isIdCar(s: string): boolean
    /**
     * 纯数字密码验证
     * @param s 字符串或者数字
     * @param len 最小长度，默认6
     * @param maxLen 最大长度，默认20
     * @returns Boolean
     */
    isPasswordOfNumber(s: number | string, le: number, maxLen: number): boolean
    /**
     * 密码验证
     * @param s 字符串或者数字
     * @param len 最小长度，默认6
     * @param maxLen 最大长度，默认20
     * @param model 0数字和英文，1数字，英文必须包含，不允许有特殊字符，2数字和字母必须包含，可以有特殊字符。
     * @returns Boolean
     */
    isPasswordOfOther(s: string | number, len: number, maxLen: number, model: number): boolean
    /**
     * 是否是一个有效的日期
     * @param s 字符串，数字，日期对象
     * @returns Boolean
     */
    isDate(s: string | number | Date): boolean
    /**
     * 显示信息
     * @param word 标题
     * @param mask 不允许穿透
     * @param icon 图标
     */
    toast(word: string, mask?: boolean, icon?: any): void
    /**
     * 获取屏幕窗口安全高度和宽度
     * 注意是针对种屏幕的统一计算，统一高度，不再让uni获取有效高度而烦恼。
     * 请一定要在onMounted或者onLoad中调用，否则不准确在h5端。
     * @return {height,width,top,isCustomHeader,sysinfo}
     */
    getWindow(): {
      width: number
      height: number
      top: number
      bottom: number
      statusBarHeight: number
      isCustomHeader: boolean
      sysinfo: UniApp.GetSystemInfoResult
    }

    /**
     * 打开页面路径
     * @param url string 打开的页面路径
     * @param type openUrlType "navigate" | "redirect" | "reLaunch" | "switchTab" | "navigateBack"
     */
    routerTo(url: string, type?: openUrlType): void
    /**
     * 将rpx转换为px
     * @param v 待转换的数字
     * @param screenWidth 屏幕的宽度，如果不提供默认自动获取
     * @return number
     */
    torpx(v: number, screenWidth?: number): number
    /**
     * 将rpx转换为px
     * @param v 待转换的数字
     * @return number
     */
    topx(v: number, screenWidth?: number): number
    /**
     * 在下一次前执行回调函数
     * @param callback 回调函数
     * @returns 一个id值，取消时cancelAnimationFrame(id)来取消
     */
    requestAnimationFrame(callback: Function): number
    /**
     * 取消回调执行
     * @param id requestAnimationFrame产生的id
     */
    cancelAnimationFrame(id: number): void
  }
  tmicon: Array<{
    font: string
    prefix: string
    fontJson: Array<{
      icon_id: string
      name: string
      font_class: string
      unicode: string
      unicode_decimal: number
    }>
  }>
  /**tmui3.0的全局配置，以代替router,theme等的外围文件夹。解耦相关目录 */
  config: Tmui.tmuiConfig
}
